#version 120 

uniform sampler2D positions;
uniform sampler2D velocities;
uniform sampler2D infos;
uniform sampler2D heightMap;

uniform float deltaTime;

uniform int dataW;
uniform int dataH;
uniform int nConstraints;
uniform float resilience;
uniform float exponent;
uniform vec3 scale;

vec2 lookup (vec2 coords) {
	return vec2  ((float(coords.x)+0.5)/dataW, (float(coords.y)+0.5)/dataH);
}


float terrainHeight (vec2 terrainPos){
    //return pow ((float)texture2D(texture, terrainPos), exponent);
    return texture2D (heightMap, lookup(terrainPos)).x * scale.y;
}

void main(){
	
	vec3 position    = texture2D (positions, gl_TexCoord[0].xy).xyz;
	vec3 newVelocity = texture2D (velocities, gl_TexCoord[0].xy).xyz;
	vec4 newInfo     = texture2D (infos, gl_TexCoord[0].xy);

	// move
	vec3 newPosition = position + newVelocity*deltaTime;
	
    // get terrain hight for future xz position
    vec2 terrainPos  = position.xz / scale.xz;
    float height = terrainHeight(terrainPos+vec2(dataW/2, dataH/2));
    
    if (newPosition.y < height - 150) {
        // Calculate normal vector.
        vec3 vertex0 = vec3(0, height, 0);
        vec3 vertex1 = vec3 (scale.x, terrainHeight (terrainPos + vec2 (1, 0)), 0);
        vec3 vertex2 = vec3 (0, terrainHeight (terrainPos + vec2 (0, 1)), scale.z);
        
        vec3 n = normalize(cross(vertex1 - vertex0, vertex2 - vertex0));
        
        if (n.y < 0) {
            n *= -1;
        }
        newVelocity = resilience*(newVelocity - 2*n*dot (n, newVelocity));
    }
    
    
	// lifetime
	if (newInfo.x>0) {
		newInfo.x -= deltaTime;
	}
	else {
		newInfo.x = 0;
	}
	
	gl_FragData[0] = vec4(newPosition,1);
	gl_FragData[1] = vec4(newVelocity,1);
	gl_FragData[2] = newInfo; 
}